#pragma once
#include <iostream>
#include <pthread.h>
#include <string>
#include <vector>
#include <Task.hpp>
#include <queue>
#define defaultnum 5

//线程池是先提前创建多个线程，当该线程池接收到任务时，会迅速的运行任务！

//tips:类中的成员函数可以嵌套类中的其他被private,protected,public限定的成员函数、变量。一个类对象被创建后，
//调用其内部的成员函数，每个非静态成员函数都有一个this指针(被创建的类对象的指针)，通过this指针调用其他成员函数

struct ThreadData
{
    pthread_t tid;
    std::string threadname;
};

template <class T>
class ThreadPool
{
    // 封装常见对线程的操作
public:
    void Lock()
    {
        pthread_mutex_lock(&mutex);
    }
    void UnLock()
    {
        pthread_mutex_unlock(&mutex);
    }
    void Dormancy() // 休眠
    {
        pthread_cond_wait(&cond, &mutex);
    }
    void WakeUp()
    {
        pthread_cond_signal(&cond);
    }

public:
    std::string GetThreadName(pthread_t tid)//通过线程tid获取线程名
    {
        for(const auto& e:pd)
        {
            if(e.tid == tid)
            {
                return e.threadname;
            }
        }
    }

    // 线程启动函数在类内声明定义时，由于每个正常类内成员函数都有一个类对象的this指针该函数只允许有一个参数,加static后就
    // 无this指针了(还可以将该函数声明声明定义在类外)，但是被static修饰后不能直接的访问类中的其他没被static修饰的成员函数与变量
    static void *HandlerTask(void *argc) // 消费任务
    {
        threadPool *pp = static_cast<ThreadPool *>(argc);
        while (true)
        {
            // pthread_detach(pthread_self());
            pp->Lock();
            if (0 == pp->tasks.size())
            {
                pp->Wait();
            }
            const T &task = pp->Pop();
            pp->UnLock();
            std::cout<<GetThreadName(pthread_self())<<" runs"std::endl;
            task();
        }
    }
    void Start() // 创建线程后线程开始运行
    {
        int num = pd.size();
        for (int i = 1; i <= num; i += 1)
        {

            pthread_create(&(tasks[i - 1].tid), nullptr, Handler, this);
            pd[i-1].threadname = "Thread-"+std::to_string(num);//初始化pd中ThreadData结构体中的线程名
            std::cout << pd[i-1].threadname << " is created" << std::endl;
        }
    }
    const T Pop() // 消费者：线程进行的操作
    {
        const T &tmp = tasks.front();
        tasks.pop();
        return tmp;
    }

    void Push(const T &task) // 向队列tasks中添加任务，访问共享堆资源要加锁。
    {
        Lock();
        if (tasks.empty())
            tasks.push(task);
        WakeUp();
        UnLock();
    }

    //创建单例
    static ThreadPool<T>* GetInstance()  //静态成员函数和成员变量受权限限定符的影响
    {
        if(nullptr == _tp)
        {
            _tp = new PthreadPool<T>();
        }
        return _tp;
    }

    private:
    ThreadPool(int num = defaultnum)
    {
        pd.resize(num);
        pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
        pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
    }
    ThreadPool(const ThreadPool<T>& tp)=delete;

    ThreadPool<T> operator=(const ThreadPool<T>& tp)=delete;

    ~ThreadPool()
    {
        // 等待线程 （或者分离线程）
        for (auto e : q)
        {
            pthread_join(e.tid, nullptr); // pthread_join等待线程时是阻塞的
        }
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&cond);
    }

private:
    std::vector<ThreadData> pd; // 存储创建线程的tid
    std::queue<T> tasks;         // 存储任务的队列
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    static ThreadPool<T>* _tp;
};

//初始化静态成员变量
template<class T>
ThreadPool<T>* ThreadPool<T>::_tp = nullptr;